//备注：拷贝代码请加上作者信息
//作者：王海涛
//邮箱：1126471088@qq.com
//版本：V0.1.2
#include "app_oled.h"

TaskHandle_t WHT_OLED_Task_Handle = NULL;                   //任务句柄


/*****************************链表结构体定义************************************/
/*链表节点*/
typedef struct xList_Node_t
{
    uint32_t Node_Number;         //节点序号
    struct xList_Node_t* Next;    //下一个节点
    struct xList_Node_t* Previous;//上一个节点
    void* Home;                   //家
    void (*Display_Func)(void);   //操作显示函数
}WHT_OLED_List_Node_t;

/*链表头节点*/
typedef struct xList_Home
{
    uint32_t Node_Count;        //节点个数
    WHT_OLED_List_Node_t* Index;//节点索引指针
    WHT_OLED_List_Node_t End;   //最后一个节点
}WHT_OLED_List_Home_t;
/*****************************链表结构体定义************************************/

/**********************************链表处理************************************/

/* 链表根节点初始化 */
void List_Home_Init(WHT_OLED_List_Home_t* const list_home)
{
	/* 将链表索引指针指向最后一个节点 */
	list_home->Index = &list_home->End;

	/* 将链表最后一个节点的辅助排序的值设置为最大，确保该节点就是链表的最后节点 */
	list_home->End.Node_Number = 0xffffffffUL;

    /* 将最后一个节点的Next和Previous指针均指向节点自身，表示链表为空 */
	list_home->End.Next = &list_home->End;
	list_home->End.Previous = &list_home->End;

	/* 初始化链表节点计数器的值为0，表示链表为空 */
	list_home->Node_Count = 0U;

    list_home->End.Home = (void*)list_home;
    list_home->End.Display_Func = NULL;
}

/* 节点初始化 */
void List_Node_Init(WHT_OLED_List_Node_t* const list_node)
{
	/* 初始化该节点所在的链表家为空，表示节点还没有插入任何链表家 */
	list_node->Home = NULL;
}

/* 将节点插入到链表的尾部 */
void List_Node_Insert_Home_End(WHT_OLED_List_Home_t* const list_home, WHT_OLED_List_Node_t* const new_list_node)
{
	WHT_OLED_List_Node_t* const Index = list_home->Index;

	new_list_node->Next = Index;
	new_list_node->Previous = Index->Previous;
	Index->Previous->Next = new_list_node;
	Index->Previous = new_list_node;

	/* 记住该节点所在的链表 */
	new_list_node->Home = (void*)list_home;

	/* 链表节点计数器++ */
	list_home->Node_Count++;
}

/* 将节点按照升序排列插入到链表 */
void List_Node_Insert_Home( WHT_OLED_List_Home_t* const list_home, WHT_OLED_List_Node_t* const new_list_node)
{
	WHT_OLED_List_Node_t* node;
	
	/* 获取节点的排序辅助值 */
	const uint32_t number = new_list_node->Node_Number;

	/* 寻找节点要插入的位置 */
	if (number == 0xffffffffUL)
	{
		node = list_home->End.Previous;
	}
	else
	{
		for (node = &list_home->End; node->Next->Node_Number <= number; node = node->Next)
		{
			/* 没有事情可做，不断迭代只为了找到节点要插入的位置 */
		}
	}

	new_list_node->Next = node->Next;
	new_list_node->Next->Previous = new_list_node;
	new_list_node->Previous = node;
	node->Next = new_list_node;

	/* 记住该节点所在的链表 */
	new_list_node->Home = (void*)list_home;

	/* 链表节点计数器++ */
	list_home->Node_Count++;
}

/* 将节点从链表中删除并返回家列表中节点个数 */
uint32_t List_Node_Remove(WHT_OLED_List_Node_t* const list_node)
{
	/* 获取节点所在的链表 */
	WHT_OLED_List_Home_t* const pxList = (WHT_OLED_List_Home_t*) list_node->Home;

	list_node->Next->Previous = list_node->Previous;
	list_node->Previous->Next = list_node->Next;

	/* Make sure the index is left pointing to a valid item. */
	if (pxList->Index == list_node)
	{
		pxList->Index = list_node->Previous;
	}

	/* 初始化该节点所在的链表为空，表示节点还没有插入任何链表 */
	list_node->Home = NULL;
	
	/* 链表节点计数器-- */
	pxList->Node_Count--;

	/* 返回链表中剩余节点的个数 */
	return pxList->Node_Count;
}
/**********************************链表处理************************************/


static uint8_t u8g2_gpio_and_delay_stm32(U8X8_UNUSED u8x8_t *u8x8, U8X8_UNUSED uint8_t msg, U8X8_UNUSED uint8_t arg_int, U8X8_UNUSED void *arg_ptr)
{
    return 1; // command processed successfully.

	switch(msg)
    {
	case U8X8_MSG_GPIO_AND_DELAY_INIT:
	    break;
	case U8X8_MSG_DELAY_MILLI:
		//WHT_Delay_ms(arg_int);
	    break;
	case U8X8_MSG_GPIO_I2C_CLOCK:		
        break;							
    case U8X8_MSG_GPIO_I2C_DATA:			
        break;
	default:	
		return 0;
	}
	return 1; // command processed successfully.
}

static uint8_t u8x8_byte_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
    static uint8_t buffer[32];		/* u8g2/u8x8 will never send more than 32 bytes between START_TRANSFER and END_TRANSFER */
    static uint8_t buf_idx;
    
    switch(msg)
    {
    case U8X8_MSG_BYTE_SEND:
        memcpy(&buffer[buf_idx], arg_ptr, arg_int);
        buf_idx += arg_int;     
        break;
    case U8X8_MSG_BYTE_INIT:
        /* add your custom code to init i2c subsystem */
        break;
    case U8X8_MSG_BYTE_SET_DC:
        /* ignored for i2c */
        break;
    case U8X8_MSG_BYTE_START_TRANSFER:
        buf_idx = 0;
        break;
    case U8X8_MSG_BYTE_END_TRANSFER:
        WHT_OLED_Driver.WHT_Write(buffer, buf_idx);
        break;
    default:
        return 0;
    }
    return 1;
}


static u8g2_t u8g2;

static WHT_OLED_List_Home_t WHT_OLED_List_Home1;

static WHT_OLED_List_Node_t WHT_OLED_List_Node1;
static WHT_OLED_List_Node_t WHT_OLED_List_Node2;
static WHT_OLED_List_Node_t WHT_OLED_List_Node3;


/*刷新菜单，只支持u8g2_font_wqy12_t_chinese1字体*/
static void WHT_OLED_Refresh_Menu(const char* home_menu, const char* const menu_handle[], uint8_t menu_count, uint8_t* const menu_number)
{
#define Max_Count  4

    u8g2_ClearBuffer(&u8g2);
    /*画圆角方框*/
    u8g2_DrawRFrame(&u8g2, 0, 0, u8g2.width, 16, 5);
    u8g2_DrawRFrame(&u8g2, 0, 16, u8g2.width, u8g2.height - 16, 5);
    /*居中主菜单*/
    u8g2_DrawUTF8(&u8g2, (u8g2.width - 6 * strlen(home_menu)) / 2, 12, home_menu);

    if (*menu_number >= menu_count)
        *menu_number = 0;

    if (menu_count > Max_Count)
        menu_count = Max_Count;

    if (*menu_number < Max_Count)
    {
        for (size_t i = 1; i <= menu_count; i++)
            u8g2_DrawUTF8(&u8g2, 5, 16 + 11 * i, menu_handle[i - 1]);
        u8g2_DrawButtonUTF8(&u8g2, 5, 16 + 11 * (*menu_number + 1), U8G2_BTN_BW1, 0, 1, 0, menu_handle[*menu_number]);
    }
    else
    {
        for (size_t i = 1; i < Max_Count; i++)
            u8g2_DrawUTF8(&u8g2, 5, 16 + 11 * i, menu_handle[*menu_number - Max_Count + i]);
        u8g2_DrawButtonUTF8(&u8g2, 5, 16 + 11 * Max_Count, U8G2_BTN_BW1, 0, 1, 0, menu_handle[*menu_number]);
    }
    u8g2_SendBuffer(&u8g2);
}


/*
u8g2_font_ncenB08_tr内存最小和u8g2_font_wqy12_t_chinese1
*/
static void OLED_Home(void)
{
    static const char* const Menu[] = { "Set", "Version", "Info","Name","Email","返回" };
    static uint8_t Number = 0;//用户上下选择此值会加减操作

    WHT_OLED_Refresh_Menu("HOME", Menu, sizeof(Menu) / sizeof(Menu[0]), &Number);

    uint32_t Keys_Notify_Value = ulTaskNotifyTake(pdTRUE, portMAX_DELAY);//死等待按键操作

    if (Keys_Notify_Value & 0x01)//框选序号
        Number++;
    if (Keys_Notify_Value & 0x02)//按下选中
    {
        switch (Number)
        {
        case 3://name
            break;
        case 4://email
            break;
        case 5://主HOME
            Number = 0;
            break;
        default:
            for (size_t i = 0; i <= Number; i++)
            {
                WHT_OLED_List_Home1.Index = WHT_OLED_List_Home1.Index->Next;
            }
            break;
        }
    }
}

static void OLED_Node1(void)
{
    static const char* const Menu[] = { "LM", "LED","返回" };
    static uint8_t Number = 0;

    WHT_OLED_Refresh_Menu("SET", Menu, sizeof(Menu) / sizeof(Menu[0]), &Number);

    uint32_t Keys_Notify_Value = ulTaskNotifyTake(pdTRUE, portMAX_DELAY);//死等待按键操作

    if (Keys_Notify_Value & 0x01)//框选序号
        Number++;
    if (Keys_Notify_Value & 0x02)//按下选中
    {
        static uint8_t LM_Grade = 8;
        uint8_t buff[20];

        switch (Number)
        {
        case 0://LM
            do
            {
                WHT_OLED_Driver.WHT_Set_LM(LM_Grade * 31);
                u8g2_ClearBuffer(&u8g2);
                u8g2_DrawUTF8(&u8g2, (u8g2.width - 6 * 2) / 2, 12, Menu[0]);
                sprintf(buff, "Grade %d", LM_Grade);
                u8g2_DrawStr(&u8g2, (u8g2.width - 6 * 7) / 2, 16 + 12, buff);
                u8g2_DrawBox(&u8g2, (u8g2.width - 32) / 2, 32, 32, 32);
                u8g2_SendBuffer(&u8g2);

                uint32_t Keys_Notify_Value = ulTaskNotifyTake(pdTRUE, portMAX_DELAY);//死等待按键操作
                if (Keys_Notify_Value & 0x01)//框选序号
                {
                    LM_Grade = LM_Grade == 8 ? 1 : LM_Grade + 1;
                }
                if (Keys_Notify_Value & 0x02)//确认并返回
                    break;
            } while (1);
            break;
        case 1://LED
            do
            {
                u8g2_ClearBuffer(&u8g2);
                u8g2_DrawUTF8(&u8g2, (u8g2.width - 6 * 3) / 2, 12, Menu[1]);

                u8g2_DrawStr(&u8g2, (u8g2.width - 6 * 17) / 2, 16 + 12, "Waiting Add Func");

                u8g2_SendBuffer(&u8g2);

                uint32_t Keys_Notify_Value = ulTaskNotifyTake(pdTRUE, portMAX_DELAY);//死等待按键操作
                if (Keys_Notify_Value & 0x01)//框选序号
                {
                    break;
                }
                if (Keys_Notify_Value & 0x02)//确认并返回
                    break;
            } while (1);
            break;
        case 2://返回上一层
            Number = 0;
            ((WHT_OLED_List_Home_t*)WHT_OLED_List_Node2.Home)->Index = &((WHT_OLED_List_Home_t*)WHT_OLED_List_Node1.Home)->End;
            //WHT_OLED_List_Home1.Index = WHT_OLED_List_Home1.Index->Previous;
            break;
        }
    }
}

static void OLED_Node2(void)
{
    u8g2_ClearBuffer(&u8g2);
    u8g2_DrawUTF8(&u8g2, (u8g2.width - 6 * 7) / 2, 12, "VERSION");
    u8g2_DrawUTF8(&u8g2, (u8g2.width - 6 * 15) / 2, 16 + 12, "Version: V0.1.0");
    u8g2_SendBuffer(&u8g2);

    uint32_t Keys_Notify_Value = ulTaskNotifyTake(pdTRUE, portMAX_DELAY);//死等待按键操作

    //WHT_OLED_List_Home1.Index = WHT_OLED_List_Home1.Index->Previous;
    ((WHT_OLED_List_Home_t*)WHT_OLED_List_Node2.Home)->Index = &((WHT_OLED_List_Home_t*)WHT_OLED_List_Node2.Home)->End;
}

static void OLED_Node3(void)
{
    u8g2_ClearBuffer(&u8g2);
    u8g2_DrawUTF8(&u8g2, (u8g2.width - 6 * 4) / 2, 12, "INFO");
    u8g2_DrawUTF8(&u8g2, (u8g2.width - 6 * 17) / 2, 16 + 12 +0, "CPU: STM32F103");
    u8g2_DrawUTF8(&u8g2, (u8g2.width - 6 * 17) / 2, 16 + 24 +2, "OLED: SSD1306");
    u8g2_DrawUTF8(&u8g2, (u8g2.width - 6 * 17) / 2, 16 + 32 +2, "I2C : 500Kbps");
    u8g2_SendBuffer(&u8g2);

    uint32_t Keys_Notify_Value = ulTaskNotifyTake(pdTRUE, portMAX_DELAY);//死等待按键操作

    //WHT_OLED_List_Home1.Index = WHT_OLED_List_Home1.Index->Previous;
    ((WHT_OLED_List_Home_t*)WHT_OLED_List_Node2.Home)->Index = &((WHT_OLED_List_Home_t*)WHT_OLED_List_Node3.Home)->End;
}


static void WHT_OLED_Start_Logo(void)
{
    u8g2_SetFont(&u8g2, u8g2_font_wqy12_t_chinese1);
    u8g2_ClearBuffer(&u8g2);
    u8g2_DrawUTF8(&u8g2, (u8g2.width - 6 * 16) / 2, 12, "Hello Word  U8G2");

    u8g2_DrawRFrame(&u8g2, 0, 30, u8g2.width, 12+2, 5);//画圆角的长度和宽度与圆角半径有联系
    for (size_t i = 0; i <= u8g2.width; i+=4)
    {
        u8g2_DrawRBox(&u8g2, i, 30, 4, 12+2, 2);
        u8g2_SendBuffer(&u8g2);
        vTaskDelay(1);
    }
}

static void WHT_OLED_List_Init(void)
{
    List_Home_Init(&WHT_OLED_List_Home1);
    List_Node_Init(&WHT_OLED_List_Node1);

    WHT_OLED_List_Home1.End.Display_Func = OLED_Home;

    WHT_OLED_List_Node1.Node_Number = 1;
    WHT_OLED_List_Node1.Display_Func = OLED_Node1;

    WHT_OLED_List_Node2.Node_Number = 2;
    WHT_OLED_List_Node2.Display_Func = OLED_Node2;

    WHT_OLED_List_Node3.Node_Number = 3;
    WHT_OLED_List_Node3.Display_Func = OLED_Node3;

    List_Node_Insert_Home(&WHT_OLED_List_Home1, &WHT_OLED_List_Node1);
    List_Node_Insert_Home(&WHT_OLED_List_Home1, &WHT_OLED_List_Node2);
    List_Node_Insert_Home(&WHT_OLED_List_Home1, &WHT_OLED_List_Node3);
}


static void WHT_OLED_Task(void* pvParameters)
{
    ////OLED_TEST_FUNC();//与U8G2配置有些冲突，2则不能混用，切记
    WHT_OLED_Driver.WHT_OLED_Init();

    u8g2_Setup_ssd1306_i2c_128x64_noname_f(&u8g2, U8G2_R0, u8x8_byte_hw_i2c, u8g2_gpio_and_delay_stm32);
    u8g2_InitDisplay(&u8g2);     //send init sequence to the display, display is in sleep mode after this,
    u8g2_ClearDisplay(&u8g2);
    u8g2_SetPowerSave(&u8g2, 0); //wake up display

    WHT_OLED_Start_Logo();
    WHT_OLED_List_Init();

    for (; ;)
    {
        WHT_OLED_List_Home1.Index->Display_Func();//这个地方将会进入OLED世界
    }
}



void WHT_OLED_Install(uint8_t task_priority)
{
    BaseType_t xreturn;

    xreturn = xTaskCreate(WHT_OLED_Task, "WHT_OLED_Task", 256, NULL, task_priority, &WHT_OLED_Task_Handle);
    if (xreturn == pdPASS)
        printf("WHT:OLED Task Create OK!\r\n");
    else
        printf("WHT:OLED Task Create Error!\r\n");
}
